home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
BPL70N16
/
ARISOURC.ZIP
/
FPEXP.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-03-07
|
11KB
|
241 lines
; *******************************************************
; * *
; * Turbo Pascal Runtime Library Version 7.0 *
; * Real Exponentiation *
; * *
; * Copyright (C) 1989-1993 Norbert Juffa *
; * *
; *******************************************************
TITLE FPEXP
CODE SEGMENT BYTE PUBLIC
ASSUME CS:CODE
; Externals
EXTRN RealAdd:NEAR,RealSub:NEAR,RealMul:NEAR,RealFloat:NEAR
EXTRN RealTrunc:NEAR,RealSqr:NEAR,RealDivRev:NEAR
EXTRN RealMulNoChk:NEAR,RealReduceMP:NEAR,ROverflow:NEAR
EXTRN RealMulF:NEAR,RealMulFNoChk:NEAR
; Publics
PUBLIC RExp
IFDEF EXTENSIONS
PUBLIC RPower2,RPower10
ENDIF
;-------------------------------------------------------------------------------
; Routines RExp, RPower2, and RPower10 exponentiate their argument x to base e,
; base 2, and base 10, respectively. All routines do the exponentiation of an
; argument x by calculating e^g * 2^n, where g is in -0.5*ln(2)..0.5*ln(2).
; While 2^n is a simple scaling operation, e^g is computed using a rational
; approximation of the Pade type. The computation of i and g differs for the
; three functions. For RPower2, n is computed as n = Round (x), and g as g =
; (x - n) * ln (2). For RExp, the computation proceeds as follows: n = Round
; (x/ln(2)), g = x - ln(2)*n, where ln(2) is represented by two constants c1
; and c2 that provide more than 40 bits of precision, so that the actual
; computation becomes x - c1*n - c2*n. This way, loss of accuracy due to the
; argument reduction is prevented. The computation of RPower10 is similar to
; that of the RExp function n = Round (x/log10(2)), g = x - log10(2) * n by
; the multiple precision process described above. Finally, g = g * ln(10).
; Actually, these different argument reduction schemes are all derived from
; the same process by elimination of unnecessary steps: n = Round (x/logB (2)),
; g = (x - n*logB(2)) * ln (B), where B is the base for exponentation.
;
; If the result of the exponentiation routines underflows the floating point
; format, zero is returned. If the computation results in overflow, error 205
; is returned through the error handler.
;
; GPZ := (2.001347076967e1*g^2+8.408086858319e2)*g
; QZ := (g^2+1.801617224813e2)*g^2+1.681617371664e3
;
; e^g := 2 * (0.5 + GPZ / (QZ - GPZ))
;
; This approximation has a theoretical maximum relative error of 2.98e-14.
; Maximum observed error when evaluated in REAL arithmetic is 1.74e-12.
;
; INPUT: DX:BX:AX argument
;
; OUTPUT: DX:BX:AX 2^argument, e^argument, 10^argument depending on function
;
; DESTROYS: AX,BX,CX,DX,SI,DI,Flags
;-------------------------------------------------------------------------------
IFDEF EXTENSIONS
RPower10 PROC FAR
PUSH BP ; save caller's framepointer
MOV BP,OFFSET Pow10Cst; address table of constants for pow10
JMP $power_10 ; compute power of ten
Pow10Cst DW 0007Fh, 09A84h, 09A20h ; log(2)-eps = 3.010299955495e-1
DW 0005Fh, 0F799h, 0FBCFh ; eps = 1.145110089921e-10
DW 0CD82h, 0784Bh, 0549Ah ; 1/log(2) = 3.321928094887e+0
DW 0AB82h, 08DDDh, 0135Dh ; ln (10) = 2.302585092994e+0
RPower10 ENDP
ALIGN 4
RPower2 PROC FAR
PUSH BP ; save caller's framepointer
MOV BP, OFFSET Pow2Cst-18;
PUSH AX ; save
MOV SI, BX ; x
MOV DI, DX ; ditto
MOV CH, 0FFh ; signal rounding desired
CALL RealTrunc ; compute n := round (x)
POP CX ; removed saved word
CMP CL, 88h ; abs (x) < 128 ?
JNB $argumnt_err ; no, overflow or underflow
PUSH AX ; save n
PUSH CX ; save lsw of x
CALL RealFloat ; compute float(n)
POP CX ; restore x to DI:SI:CX
XOR DH, 80h ; -n
CALL RealAdd ; compute t := -n + x = n - x
JMP $power_2 ; compute power of two
Pow2Cst DW 0D280h, 017F7h, 03172h ; ln (2) = 6.931471805599e-1
RPower2 ENDP
ENDIF
RExp_Ext PROC FAR
$argumnt_err:POP BP ; restore caller's frame pointer
OR DI, DI ; argument negative ?
JS $exp_zero ; yes, result = 0 to machine precision
JMP $exp_overfl ; no, overflow, signal error
$exp_zero: XOR AX, AX ; load
MOV BX, AX ; a
CWD ; zero
RET ; done
RExp_Ext ENDP
ALIGN 4
RExp PROC FAR
PUSH BP ; save frame pointer
MOV BP, OFFSET PowECst; pointer to table of constants
$power_10: PUSH DX ; save
PUSH BX ; argument x
PUSH AX ; on stack
MOV CX, CS:[BP+12] ; load
MOV SI, CS:[BP+14] ; constant
MOV DI, CS:[BP+16] ; 1/lg(2)
CALL RealMulFNoChk ; compute y := x/lg(2) (DI:SI:CX <> 0)
POP CX ; get
POP SI ; back
POP DI ; x
CMP AL, 88h ; abs (y) < 128 ?
JNB $argumnt_err ; no, underflow or overflow
PUSH CX ; save lsw of x
MOV CH, -1 ; signal rounding
CALL RealTrunc ; n = round (y)
POP CX ; get back lsw of x
PUSH AX ; save n
PUSH CX ; save lsw of x
CALL RealFloat ; convert n to floating-point
POP CX ; get back lsw of x
CALL RealReduceMP ; compute t = x - n*c1 - n*c2
IFDEF EXTENSIONS
CMP BP, OFFSET PowECst; function = e^x ?
JE $approx ; yes, compute approximation with g = t
$power_2: MOV CX, CS:[BP+18] ; load
MOV SI, CS:[BP+20] ; constant
MOV DI, CS:[BP+22] ; 1/lg(2)
CALL RealMulNoChk ; compute g := t/lg(2) (DI:SI:CX <> 0)
ENDIF
$approx: PUSH DX ; save
PUSH BX ; g on
PUSH AX ; stack
CALL RealSqr ; compute z := g^2
POP CX ; get
POP SI ; g from
POP DI ; stack
PUSH DX ; save
PUSH BX ; z on
PUSH AX ; stack
PUSH DI ; save
PUSH SI ; g on
PUSH CX ; stack
MOV CX, 01A85h ; load real
MOV SI, 09690h ; constant
MOV DI, 0201Bh ; 2.001347076967e1
CALL RealMulFNoChk ; multiply by z (DI:SI:CX <> 0)
MOV CX, 0388Ah ; load
MOV SI, 0C182h ; real constant
MOV DI, 05233h ; 8.408086858319e2
CALL RealAdd ; make sum
POP CX ; get
POP SI ; g from
POP DI ; stack
CALL RealMulF ; compute GPZ
POP CX ; get
POP SI ; z from
POP DI ; stack
PUSH DX ; save
PUSH BX ; GPZ
PUSH AX ; on stack
MOV AX, 00088h ; load
MOV BX, 066A5h ; real constant
MOV DX, 03429h ; 1.801617224813e2
PUSH DI ; save
PUSH SI ; z on
PUSH CX ; stack
CALL RealAdd ; add z
POP CX ; get
POP SI ; z from
POP DI ; stack
CALL RealMulF ; multiply result by z
MOV CX, 0388Bh ; load
MOV SI, 0C182h ; real constant
MOV DI, 05233h ; 1.681617371664e3
CALL RealAdd ; compute QZ
POP CX ; get
POP SI ; GPZ from
POP DI ; stack
PUSH DI ; save
PUSH SI ; GPZ on
PUSH CX ; stack
CALL RealSub ; compute QZ - GPZ
POP CX ; get
POP SI ; GPZ from
POP DI ; stack
CALL RealDivRev ; compute GPZ / (QZ-GPZ)
MOV CX, 80h ; load
XOR SI, SI ; real constant
MOV DI, SI ; 0.5
CALL RealAdd ; compute 0.5 + GPZ / (QZ-GPZ)
POP CX ; get n
INC CX ; compute n+1
ADD AL, CL ; adjust exponent by adding n+1
POP BP ; restore caller's frame pointer
JZ $exp_overfl ; overflow error if exponent overflows
RET ; done
$exp_overfl: JMP ROverflow ; error 205, floating point overflow
PowECst DW 00080h, 017F7h, 0B172h ; ln(2)-eps = 6.931471803691e-1
DW 00060h, 079ACh, 0D1CFh ; eps = 1.908214929385e-10
DW 05C81h, 03B29h, 038AAh ; 1/ln(2) = 1.442695040889e+0
RExp ENDP
ALIGN 4
CODE ENDS
END